﻿namespace DomainServices.Tools.Pdb.SymStore
{
    using System;
    using System.Diagnostics.SymbolStore;
    using System.Runtime.InteropServices;

    internal static class SymbolAccess
    {
        private static Guid dispenserClassID = new Guid(0xe5cb7a31, 0x7512, 0x11d2, 0x89, 0xce, 0, 0x80, 0xc7, 0x92, 0xe5, 0xd8);
        private static Guid dispenserIID = new Guid(0x809c652e, 0x7396, 0x11d2, 0x97, 0x71, 0, 160, 0xc9, 180, 0xd5, 12);
        private static Guid importerIID = new Guid(0x7dac8207, 0xd3ae, 0x4c75, 0x9b, 0x67, 0x92, 0x80, 0x1a, 0x49, 0x7d, 0x44);
        private const int OPEN_READ = 0;
        private const int OPEN_WRITE = 1;

        internal static ISymbolReader GetReaderForFile(string pathModule)
        {
            return GetReaderForFile(pathModule, null);
        }

        internal static ISymbolReader GetReaderForFile(string pathModule, string searchPath)
        {
            return GetReaderForFile(SymbolFormat.PDB, pathModule, searchPath);
        }

        internal static ISymbolReader GetReaderForFile(SymbolFormat symFormat, string pathModule, string searchPath)
        {
            object obj2;
            object obj3;
            ISymbolReader reader;
            if (symFormat != SymbolFormat.PDB)
            {
                throw new ArgumentException("Invalid format", "symFormat");
            }
            SymbolBinder binder = new SymbolBinder();
            NativeMethods.CoCreateInstance(ref dispenserClassID, null, 1, ref dispenserIID, out obj2);
            ((IMetaDataDispenserPrivate) obj2).OpenScope(pathModule, 0, ref importerIID, out obj3);
            IntPtr zero = IntPtr.Zero;
            try
            {
                zero = Marshal.GetComInterfaceForObject(obj3, typeof(IMetadataImportPrivateComVisible));
                reader = binder.GetReader(zero, pathModule, searchPath);
            }
            finally
            {
                if (zero != IntPtr.Zero)
                {
                    Marshal.Release(zero);
                }
            }
            return reader;
        }

        internal static class NativeMethods
        {
            [DllImport("ole32.dll")]
            internal static extern int CoCreateInstance([In] ref Guid rclsid, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppv);
        }
    }
}

